package cc.eddic.practice.concurrency.impl;

import cc.eddic.practice.concurrency.LogItem;
import cc.eddic.practice.concurrency.LogItemParser;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.Optional;
import java.util.regex.Pattern;

@Slf4j
@Component
@Qualifier("LogItemParserQiniuCdnImpl")
public class LogItemParserQiniuCdnImpl extends LogItemParserImpl implements LogItemParser {
    @Override
    public Optional<LogItem> parse(String line) {
        val lineMatcher = LOG_PATTERN.matcher(line);
        if (!lineMatcher.matches()) {
            log.error("Error parsing line: {}", line);
            return Optional.empty();
        }

        LocalDateTime ldt;
        try {
            ldt = LocalDateTime.parse(lineMatcher.group("timeZone"), DATE_TIME_FORMATTER);
        } catch (DateTimeParseException ex) {
            log.error("Error parsing time: {}", lineMatcher.group("timeZone"), ex);
            return Optional.empty();
        }

        int status;
        try {
            status = Integer.parseInt(lineMatcher.group("statusCode"));
        } catch (NumberFormatException ex) {
            log.error("Error parsing status: {}", lineMatcher.group("statusCode"), ex);
            return Optional.empty();
        }

        long bytes;
        try {
            bytes = Long.parseLong(lineMatcher.group("trafficSize"));
        } catch (NumberFormatException ex) {
            log.error("Error parsing bytes: {}", lineMatcher.group("trafficSize"), ex);
            return Optional.empty();
        }

        val req = request(lineMatcher.group("request"), line);
        return Optional.of(new LogItem(lineMatcher.group("clientIP"), ldt, lineMatcher.group("request"), req.getMethod(), req.getUrl(), req.getQuery(), req.getProtocol(), status, bytes, lineMatcher.group("referer"), lineMatcher.group("userAgent")));
    }

    private static final Pattern LOG_PATTERN = Pattern.compile("(?<clientIP>.+) (?<hitMiss>.+) (?<responseTime>\\d+) \\[(?<timeZone>.+)] \"(?<request>.*)\" (?<statusCode>\\d+) (?<trafficSize>\\d+) \"(?<referer>.*?)\" \"(?<userAgent>.*)\"", Pattern.UNICODE_CHARACTER_CLASS | Pattern.DOTALL);

}
